<?php
/**
 * Created by PhpStorm.
 * User: peter
 * Date: 2018/9/10
 * Time: 上午11:52
 */

namespace app\activity\logic;


use app\model\MemberLoginToken;
use app\model\WeChat;
use extend\Functions;
use extend\STATUS_CODE;
use think\facade\Cache;
use think\facade\Log;
use think\facade\Request;

class Sign
{
    /**
     * @purpose 找回密码
     * @param string $mobile
     * @param string $code
     * @param string $password
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function findPassword(
        string $mobile = '',
        string $code = '',
        string $password = ''): array
    {
        if (!$mobile) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '手机号码不能为空'
            );
        }
        if (!$code) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '验证码不能为空'
            );
        }
        if (!$password) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '密码不能为空'
            );
        }
        if (!Functions::check_mobile($mobile)) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '手机号码格式错误'
            );
        }
        $password = strtolower(trim($password));
        if (!preg_match('/^[A-Za-z0-9\-\.\_]{6,}/', $password)) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '密码格式错误,格式为6位以上,数字与字母的组合'
            );
        }
        $self_code      = (string) Cache::store('redis')->get($mobile);
        if (!$self_code) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '验证码已过期'
            );
        }
        if ($self_code !== $code) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '验证码错误...!'
            );
        }
        Cache::store('redis')->rm($mobile);
        $model        = new \app\model\Member();
        $member_info  = $model
            ->where('mobile', $mobile)
            ->field('uid,password,encrypt')
            ->find();
        if (!$member_info) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '用户不存在...!'
            );
        }
        $member_data = Functions::password($password);
        $member_result = $model
            ->isUpdate(true)
            ->save($member_data, ['uid' => $member_info->uid]);
        if ($member_result) {
            return Functions::result();
        }
        return Functions::result(
            STATUS_CODE::FAIL,
            '密码找回失败'
        );
    }

    /**
     * @purpose 通过手机验证码绑定账号
     * @param string $mobile
     * @param string $code
     * @param string $key
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function registerByMobileForNative($data): array
    {
        $member = new \app\model\Member();
        $login  = new MemberLoginToken();
        $wechat = new WeChat();
        $member->startTrans();
        $selfCode = (string)Cache::store('redis')->get($data['mobile']);
        if (!$selfCode) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '验证码已过期..!'
            );
        }
        if ($selfCode !== $data['code']) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '验证码错误...!'
            );
        }
        $member_info = $member
            ->where('mobile', $data['mobile'])
            ->field('uid,password,encrypt')
            ->find();
        if (!$member_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '用户不存在...!'
            );
        }
        $wechat_user_info = $data['wechat_user_info'];
        if (!$wechat_user_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '授权已过期,请重新授权'
            );
        }
        $member_data['avatar']          = $wechat_user_info['headimgurl'];
        $member_data['create_ip']       = Request::ip();
        $member_data['last_login_ip']   = Request::ip();
        $member_data['now_ip']          = Request::ip();
        $member_data['last_login_time'] = time();
        $member_data['now_time']        = time();
        $member_data['sex']             = $wechat_user_info['sex'];
        $member_result                  = $member
            ->isUpdate(true)
            ->save($member_data, ['uid' => $member_info->uid]);
        // 构建用户登录数据
        $login_data              = [];
        $login_data['uid']       = $member_info->uid;
        $login_data['app_token'] = strtolower(Functions::getUUID());
        RE_LOGIN_TOKEN:
        $login_data['app_token'] = strtolower(Functions::getUUID());
        if ($login->where('app_token', $login_data['app_token'])->count(1) > 0) {
            goto RE_LOGIN_TOKEN;
        }
        $login_result = true;
        // 检测是否有登录数据
        if ($login->where('uid', $member_info->uid)->count(1) > 0) {
            $login_result = $login
                ->where('uid', $member_info->uid)
                ->update($login_data);
        } else {
            $login_result = $login
                ->isUpdate(false)
                ->data($login_data)
                ->save();
        }
        // 构建微信授权数据
        $wechat_data            = [];
        $wechat_data['uid']     = $member_info->uid;
        $wechat_data['openid']  = $wechat_user_info['openid'];
        $wechat_data['unionid'] = $wechat_user_info['unionid'];
        // 检测用户数据是否有关注数据
        if (isset($wechat_user_info['subscribe'])) {
            $wechat_data['subscribe'] = $wechat_user_info['subscribe'];
        }
        // 关注时间
        if (isset($wechat_user_info['subscribe_time'])) {
            $wechat_data['subscribe_time'] = $wechat_user_info['subscribe_time'];
        }
        // 关注方式
        if (isset($wechat_user_info['subscribe_scene'])) {
            $wechat_data['subscribe_scene'] = $wechat_user_info['subscribe_scene'];
        }
        $wechat_result = true;
        if ($wechat->where('uid', $member_info->uid)->count(1) > 0) {
            $wechat_result = $wechat
                ->where('uid', $member_info->uid)
                ->update($wechat_data);
        } else {
            $wechat_result = $wechat
                ->isUpdate(false)
                ->data($wechat_data)
                ->save();
        }
        if ($member_result && $login_result && $wechat_result) {
            $member->commit();
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token'  => $login_data['app_token'],
                ]
            );
        }
        $member->rollback();
        return Functions::result(
            STATUS_CODE::SUCCESS,
            [
                'status' => STATUS_CODE::FAIL,
            ]
        );
    }

    /**
     * @purpose 注册并通过用户名绑定账号
     * @param string $username
     * @param string $password
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function registerByUsernameForNative(array $data): array
    {
        if (!$data['username']) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '用户名不能为空...!'
            );
        }
        if (!$data['password']) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '密码不能为空...!'
            );
        }
        $member = new \app\model\Member();
        $login  = new MemberLoginToken();
        $wechat = new WeChat();
        $member->startTrans();
        $member_info = $member
            ->where('username', $data['username'])
            ->field('uid,password,encrypt')
            ->find();
        if (!$member_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '用户不存在...!'
            );
        }
        if ($member_info->password !== Functions::password(trim($data['password']), $member_info->encrypt)) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '密码错误'
            );
        }
        $wechat_user_info = $data['wechat_user_info'];
        if (!$wechat_user_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '授权已过期,请重新授权'
            );
        }
        $member_data                    = Functions::password(strtolower(trim($data['password'])));
        $member_data['avatar']          = $wechat_user_info['headimgurl'];
        $member_data['create_ip']       = Request::ip();
        $member_data['last_login_ip']   = Request::ip();
        $member_data['now_ip']          = Request::ip();
        $member_data['last_login_time'] = time();
        $member_data['now_time']        = time();
        $member_data['sex']             = $wechat_user_info['sex'];
        $member_result                  = $member
            ->isUpdate(true)
            ->save($member_data, ['uid' => $member_info->uid]);
        // 构建用户登录数据
        $login_data              = [];
        $login_data['uid']       = $member_info->uid;
        $login_data['app_token'] = strtolower(Functions::getUUID());
        RE_LOGIN_TOKEN:
        $login_data['app_token'] = strtolower(Functions::getUUID());
        if ($login->where('app_token', $login_data['app_token'])->count(1) > 0) {
            goto RE_LOGIN_TOKEN;
        }
        $login_result = true;
        // 检测是否有登录数据
        if ($login->where('uid', $member_info->uid)->count(1) > 0) {
            $login_result = $login
                ->where('uid', $member_info->uid)
                ->update($login_data);
        } else {
            $login_result = $login
                ->isUpdate(false)
                ->data($login_data)
                ->save();
        }
        // 构建微信授权数据
        $wechat_data            = [];
        $wechat_data['uid']     = $member_info->uid;
        $wechat_data['openid']  = $wechat_user_info['openid'];
        $wechat_data['unionid'] = $wechat_user_info['unionid'];
        // 检测用户数据是否有关注数据
        if (isset($wechat_user_info['subscribe'])) {
            $wechat_data['subscribe'] = $wechat_user_info['subscribe'];
        }
        // 关注时间
        if (isset($wechat_user_info['subscribe_time'])) {
            $wechat_data['subscribe_time'] = $wechat_user_info['subscribe_time'];
        }
        // 关注方式
        if (isset($wechat_user_info['subscribe_scene'])) {
            $wechat_data['subscribe_scene'] = $wechat_user_info['subscribe_scene'];
        }
        $wechat_result = true;
        if ($wechat->where('uid', $member_info->uid)->count(1) > 0) {
            $wechat_result = $wechat
                ->where('uid', $member_info->uid)
                ->update($wechat_data);
        } else {
            $wechat_result = $wechat
                ->isUpdate(false)
                ->data($wechat_data)
                ->save();
        }
        if ($member_result && $login_result && $wechat_result) {
            $member->commit();
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token'  => $login_data['app_token'],
                ]
            );
        }
        $member->rollback();
        return Functions::result(
            STATUS_CODE::SUCCESS,
            [
                'status' => STATUS_CODE::FAIL,
            ]
        );

    }

    /**
     * @purpose 通过授权缓存的用户信息key注册
     * @param string $key
     * @return array
     * @throws \think\exception\PDOException
     */
    public static function registerForNative(array $wechat_user_info): array
    {
        $wechat_user_info['openid'] = '';
        return self::register($wechat_user_info, 'app');
    }

    /**
     * @
     * @param string $unionid
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function checkUnionIdForNative(string $unionid): array
    {
        $wechat      = new WeChat();
        $login       = new MemberLoginToken();
        $member      = new \app\model\Member();
        $member_info = $wechat
            ->with('member')
            ->where('unionid', $unionid)
            ->field('uid,unionid')
            ->find();
        if (!$member_info) {
            return Functions::result(
                [
                    'status' => STATUS_CODE::DATA_NOT_FIND,
                ]
            );
        }
        $login_data['app_token'] = strtolower(Functions::getUUID());
        RE_LOGIN_TOKEN:
        $login_data['app_token']        = strtolower(Functions::getUUID());
        $login_result                   = $login
            ->isUpdate(true)
            ->save($login_data, ['uid' => $member_info->uid]);
        $member_data['create_ip']       = Request::ip();
        $member_data['last_login_ip']   = Request::ip();
        $member_data['now_ip']          = Request::ip();
        $member_data['last_login_time'] = time();
        $member_data['now_time']        = time();
        $member_result                  = $member
            ->isUpdate(true)
            ->save($member_data, ['uid' => $member_info->uid]);
        if ($login_result && $member_result) {
            return Functions::result(
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token'  => $login_data['app_token'],
                ]
            );
        }
    }

    /**
     * @purpose 通过手机验证码绑定账号
     * @param string $mobile
     * @param string $code
     * @param string $key
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function registerByMobile(
        string $mobile,
        string $code,
        string $key
    ): array
    {
        if (!$mobile) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '手机号码不能为空...!'
            );
        }
        if (!$code) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '验证码不能为空...!'
            );
        }
        if (!$key) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '参数错误...!'
            );
        }

        $member = new \app\model\Member();
        $login  = new MemberLoginToken();
        $wechat = new WeChat();
        $member->startTrans();
        $selfCode = (string)Cache::store('redis')->get($mobile);
        if (!$selfCode) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '验证码已过期..!'
            );
        }
        if ($selfCode !== $code) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '验证码错误...!'
            );
        }
        $member_info = $member
            ->where('mobile', $mobile)
            ->field('uid,password,encrypt')
            ->find();
        if (!$member_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '用户不存在...!'
            );
        }
        $wechat_user_info = Cache::store('redis')->get($key);
        if (!$wechat_user_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '授权已过期,请重新授权'
            );
        }
        $wechat_user_info               = json_decode($wechat_user_info, true);
        $member_data['avatar']          = $wechat_user_info['headimgurl'];
        $member_data['create_ip']       = Request::ip();
        $member_data['last_login_ip']   = Request::ip();
        $member_data['now_ip']          = Request::ip();
        $member_data['last_login_time'] = time();
        $member_data['now_time']        = time();
        $member_data['sex']             = $wechat_user_info['sex'];
        $member_result                  = $member
            ->isUpdate(true)
            ->save($member_data, ['uid' => $member_info->uid]);
        // 构建用户登录数据
        $login_data                 = [];
        $login_data['uid']          = $member_info->uid;
        $login_data['wechat_token'] = strtolower(Functions::getUUID());
        RE_LOGIN_TOKEN:
        $login_data['wechat_token'] = strtolower(Functions::getUUID());
        if ($login->where('wechat_token', $login_data['wechat_token'])->count(1) > 0) {
            goto RE_LOGIN_TOKEN;
        }
        $login_result = true;
        // 检测是否有登录数据
        if ($login->where('uid', $member_info->uid)->count(1) > 0) {
            $login_result = $login
                ->where('uid', $member_info->uid)
                ->update($login_data);
        } else {
            $login_result = $login
                ->isUpdate(false)
                ->data($login_data)
                ->save();
        }
        // 构建微信授权数据
        $wechat_data            = [];
        $wechat_data['uid']     = $member_info->uid;
        $wechat_data['openid']  = $wechat_user_info['openid'];
        $wechat_data['unionid'] = $wechat_user_info['unionid'];
        // 检测用户数据是否有关注数据
        if (isset($wechat_user_info['subscribe'])) {
            $wechat_data['subscribe'] = $wechat_user_info['subscribe'];
        }
        // 关注时间
        if (isset($wechat_user_info['subscribe_time'])) {
            $wechat_data['subscribe_time'] = $wechat_user_info['subscribe_time'];
        }
        // 关注方式
        if (isset($wechat_user_info['subscribe_scene'])) {
            $wechat_data['subscribe_scene'] = $wechat_user_info['subscribe_scene'];
        }
        $wechat_result = true;
        if ($wechat->where('uid', $member_info->uid)->count(1) > 0) {
            $wechat_result = $wechat
                ->where('uid', $member_info->uid)
                ->update($wechat_data);
        } else {
            $wechat_result = $wechat
                ->isUpdate(false)
                ->data($wechat_data)
                ->save();
        }
        if ($member_result && $login_result && $wechat_result) {
            $member->commit();
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token'  => $login_data['wechat_token'],
                ]
            );
        }
        $member->rollback();
        return Functions::result(
            STATUS_CODE::SUCCESS,
            [
                'status' => STATUS_CODE::FAIL,
            ]
        );
    }

    /**
     * @purpose 注册并通过用户名绑定账号
     * @param string $username
     * @param string $password
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function registerByUsername(
        string $username,
        string $password,
        string $key
    ): array
    {
        if (!$username) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '用户名不能为空...!'
            );
        }
        if (!$password) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '密码不能为空...!'
            );
        }
        if (!$key) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '参数错误...!'
            );
        }
        $member = new \app\model\Member();
        $login  = new MemberLoginToken();
        $wechat = new WeChat();
        $member->startTrans();
        $member_info = $member
            ->where('username', $username)
            ->field('uid,password,encrypt')
            ->find();
        if (!$member_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '用户不存在...!'
            );
        }
        if ($member_info->password !== Functions::password(trim($password), $member_info->encrypt)) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '密码错误'
            );
        }
        $wechat_user_info = Cache::store('redis')->get($key);
        if (!$wechat_user_info) {
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '授权已过期,请重新授权'
            );
        }
        $wechat_user_info               = json_decode($wechat_user_info, true);
        $member_data                    = Functions::password(strtolower(trim($password)));
        $member_data['avatar']          = $wechat_user_info['headimgurl'];
        $member_data['create_ip']       = Request::ip();
        $member_data['last_login_ip']   = Request::ip();
        $member_data['now_ip']          = Request::ip();
        $member_data['last_login_time'] = time();
        $member_data['now_time']        = time();
        $member_data['sex']             = $wechat_user_info['sex'];
        $member_result                  = $member
            ->isUpdate(true)
            ->save($member_data, ['uid' => $member_info->uid]);
        // 构建用户登录数据
        $login_data                 = [];
        $login_data['uid']          = $member_info->uid;
        $login_data['wechat_token'] = strtolower(Functions::getUUID());
        RE_LOGIN_TOKEN:
        $login_data['wechat_token'] = strtolower(Functions::getUUID());
        if ($login->where('wechat_token', $login_data['wechat_token'])->count(1) > 0) {
            goto RE_LOGIN_TOKEN;
        }
        $login_result = true;
        // 检测是否有登录数据
        if ($login->where('uid', $member_info->uid)->count(1) > 0) {
            $login_result = $login
                ->where('uid', $member_info->uid)
                ->update($login_data);
        } else {
            $login_result = $login
                ->isUpdate(false)
                ->data($login_data)
                ->save();
        }
        // 构建微信授权数据
        $wechat_data            = [];
        $wechat_data['uid']     = $member_info->uid;
        $wechat_data['openid']  = $wechat_user_info['openid'];
        $wechat_data['unionid'] = $wechat_user_info['unionid'];
        // 检测用户数据是否有关注数据
        if (isset($wechat_user_info['subscribe'])) {
            $wechat_data['subscribe'] = $wechat_user_info['subscribe'];
        }
        // 关注时间
        if (isset($wechat_user_info['subscribe_time'])) {
            $wechat_data['subscribe_time'] = $wechat_user_info['subscribe_time'];
        }
        // 关注方式
        if (isset($wechat_user_info['subscribe_scene'])) {
            $wechat_data['subscribe_scene'] = $wechat_user_info['subscribe_scene'];
        }

        $wechat_result = true;
        if ($wechat->where('uid', $member_info->uid)->count(1) > 0) {
            $wechat_result = $wechat
                ->where('uid', $member_info->uid)
                ->update($wechat_data);
        } else {
            $wechat_result = $wechat
                ->isUpdate(false)
                ->data($wechat_data)
                ->save();
        }
        if ($member_result && $login_result && $wechat_result) {
            $member->commit();
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token'  => $login_data['wechat_token'],
                ]
            );
        }
        $member->rollback();
        return Functions::result(
            STATUS_CODE::SUCCESS,
            [
                'status' => STATUS_CODE::FAIL,
            ]
        );

    }

    /**
     * @purpose 通过授权缓存的用户信息key注册
     * @param string $key
     * @return array
     * @throws \think\exception\PDOException
     */
    public static function registerByKey(string $key = ''): array
    {
        if (!$key) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '参数错误...!'
            );
        }
        $wechat_user_info = Cache::store('redis')->get($key);
        if (!$wechat_user_info) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '请重新进行微信授权'
            );
        }
        return self::register(json_decode($wechat_user_info, true), 'wechat');
    }

    /**
     * @purpose 用户名密码登录
     * @param string $username
     * @param string $password
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function signInByPassword(
        string $username = '',
        string $password = '',
        string $client_type): array
    {
        if (!$username) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '用户名不能为空'
            );
        }
        if (!$password) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '密码不能为空'
            );
        }
        $sign_type = [];
        if (preg_match('/[\x{4e00}-\x{9fa5}]/u', $username)) {
            $sign_type['type'] = 'username';
            $sign_type['username'] = $username;
        } else {
            $sign_type = Functions::get_sign_type($username);
        }
        $member       = new \app\model\Member();
        $member_login = new MemberLoginToken();
        $member->startTrans();
        $member_info = $member
            ->where($sign_type['type'], $sign_type[$sign_type['type']])
            ->field('uid,password,encrypt,now_ip,now_time')
            ->find();
        // 如果没有找到用户信息，则通过用户名字段在查询一遍，兼容老系统用户名为手机号码的问题
        if (!$member_info) {$member
            ->where('username', $sign_type[$sign_type['type']])
            ->field('uid,password,encrypt,now_ip,now_time')
            ->find();
        }
        if (!$member_info) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '用户名或密码错误...!'
            );
        }
        $password = strtolower(trim($password));
        if ($member_info->password !== Functions::password($password, $member_info->encrypt)) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '用户名或密码错误'
            );
        }
        $token = strtolower(Functions::getUUID());
        RE_TOKEN:
        $token = strtolower(Functions::getUUID());
        if ($member_login->where($client_type . '_token', $token)->count(1) > 0) {
            goto RE_TOKEN;
        }
        $update_date                    = [];
        $update_date['last_login_ip']   = $member_info->now_ip;
        $update_date['last_login_time'] = $member_info->now_time;
        $update_date['now_ip']          = Request::ip();
        $update_date['now_time']        = time();
        $member_result                  = $member
            ->isUpdate(true)
            ->save($update_date, ['uid' => $member_info->uid]);
        if ($member_login->where(['uid' => $member_info->uid])->count(1) <= 0) {
            $login_result                   = $member_login
                ->isUpdate(false)
                ->data([
                    $client_type . '_token' => $token,
                    'uid' => $member_info->uid
                ])
                ->save();
        } else {
            $login_result                   = $member_login
                ->isUpdate(true)
                ->save([
                    $client_type . '_token' => $token,
                ], ['uid' => $member_info->uid]);
        }
        if ($member_result && $login_result) {
            $member->commit();
            return Functions::result([
                'token' => $token,
            ]);
        }
        $member->rollback();
        return Functions::result(
            STATUS_CODE::UPDATE_FAIL,
            '登录失败!'
        );

    }

    /**
     * @purpose 获取用户Token
     * @param string $code
     * @param string $token
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function token(string $code = '', string $token = '', $client_type): array
    {
        // 如果code 存在则优先处理code
        // 获取微信用户信息
        if ($code) {
            return self::sign($code);
        }
        // 客户端使用本地储存的token换取新的token
        if ($token) {
            return self::tokenToNewToken(trim($token), $client_type);
        }
        return Functions::result(
            STATUS_CODE::FAIL,
            '参数错误!'
        );
    }

    /**
     * @param $token
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private static function tokenToNewToken($token, $client_type): array
    {
        $login = new MemberLoginToken();
        // 获取用户信息
        $member_info = $login
            ->alias('l')
            ->join('member m', 'l.uid=m.uid')
            ->field('l.uid,l.wechat_token,m.uuid')
            ->where([
                'l.'.$client_type.'_token' => $token,
            ])
            ->find();
        if (!$member_info) {
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::EXPIRED_TOKEN,
                ]
            );
        }
        $_token = strtolower(Functions::getUUID());
        RE_NEW_TOKEN:
        $_token = strtolower(Functions::getUUID());
        if ($login->where($client_type.'_token', $_token)->count(1) > 0) {
            goto RE_NEW_TOKEN;
        }
        $result = $login
            ->isUpdate(true)
            ->save([$client_type.'_token' => $_token], ['uid' => $member_info->uid]);
        if ($result) {
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => 10000,
                    'token'  => $_token,
                ]
            );
        }
        return Functions::result(
            STATUS_CODE::SUCCESS,
            [
                'status' => STATUS_CODE::FAIL,
            ]
        );
    }

    /**
     * @purpose 微信授权登录
     * @param $code
     * @return array|mixed|\Requests_Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \Exception
     */
    private static function sign($code)
    {
        // 获取微信用户信息
        $wechat_user_info = self::getWeChatUserInfo($code);
        // 检测到微信返回数据错误码则直接放回
        if (isset($wechat_user_info['code'])) {
            return $wechat_user_info;
        }
        // 获取用户授权的openid
        $openid  = $wechat_user_info['openid'];
        $unionid = $wechat_user_info['unionid'];
        // 实例化微信公众号授权表模型
        $wechat = new WeChat();
        // 获取微信授权信息
        // 因为存在多终端登录问题，这个地方使用openid和unionid同时作为or的条件来获取用户信息
        $wechat_info = $wechat
            ->where('openid', $openid)
            ->whereOr('unionid', $unionid)
            ->field('uid,openid,unionid')
            ->find();
        // 检测用户是否已经在系统里面注册
        if (!$wechat_info) {
            // 暂存用户信息
            $key = Functions::getUUID();
            Cache::store('redis')->set($key, json_encode($wechat_user_info), 300);
            return Functions::result([
                'status'   => 'bind',
                'bind_key' => $key,
            ]);
            // 未注册，则进行注册并登陆
//            return self::register($wechat_user_info);
        }
        // 已经注册，则利用openid,获取中unionid进行登录
        return self::login($wechat_info->uid, $wechat_user_info);
    }

    /**
     * @purpose 用户登录
     * @param int $uid
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    private static function login(int $uid, array $wechat_user_info): array
    {
        $member = new \app\model\Member();
        $login  = new MemberLoginToken();
        $wechat = new WeChat();
        // 开启事物
        $member->startTrans();
        $member_info = $member
            ->where('uid', $uid)
            ->field('uid,uuid,now_ip,now_time')
            ->find();
        if (!$member_info) {
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::FAIL,
                ]
            );
        }
        $update                    = [];
        $update['last_login_ip']   = $member_info->now_ip;
        $update['last_login_time'] = $member_info->now_time;
        $update['now_ip']          = Request::ip();
        $update['now_time']        = time();
//        $update['avatar']          = $wechat_user_info['headimgurl'];
//        $update['nickname']        = $wechat_user_info['nickname'];
        $token = strtolower(Functions::getUUID());
        RE_TOKEN:
        $token = strtolower(Functions::getUUID());
        if ($login->where(['wechat_token' => $token])->count(1) > 0) {
            goto RE_TOKEN;
        }
        // 如果登录数据存在则更新，不存在则新增
        if ($login->where('uid', $uid)->count(1) > 0) {
            $login_result = $login
                ->isUpdate(true)
                ->save(['wechat_token' => $token], ['uid' => $uid]);
        } else {
            $login_result = $login
                ->isUpdate(false)
                ->data([
                    'wechat_token' => $token,
                ])
                ->save();
        }
        $member_result = $member
            ->isUpdate(false)
            ->save($update, ['uid' => $uid]);
        $wechat_result = true;
        if ($wechat_user_info['subscribe']) {
            $wechat_result = $wechat
                ->isUpdate(true)
                ->save([
                    'subscribe'       => $wechat_user_info['subscribe'],
                    'subscribe_time'  => $wechat_user_info['subscribe_time'],
                    'subscribe_scene' => $wechat_user_info['subscribe_scene'],
                ], ['uid' => $uid]);
        }
        if ($member_result && $login_result && $wechat_result) {
            // 提交事物
            $member->commit();
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token'  => $token,
                ]
            );
        }
        // 事物回滚
        $member->rollback();
        return Functions::result(
            STATUS_CODE::SUCCESS,
            [
                'status' => STATUS_CODE::FAIL,
            ]
        );
    }

    /**
     * @purpose 用户注册
     * @param array $wechat_user_info
     * @return array
     * @throws \think\exception\PDOException
     */
    private static function register(array $wechat_user_info, $client_type): array
    {
        $member = new \app\model\Member();
        $login  = new MemberLoginToken();
        $wechat = new WeChat();
        // 开启事物
        $member->startTrans();
        // 构建用户数据
        $member_data         = [];
        $member_data['uuid'] = strtolower(Functions::getUUID());
        RE_UUID:
        $member_data['uuid'] = strtolower(Functions::getUUID());
        if ($member->where('uuid', $member_data['uuid'])->count(1) > 0) {
            goto RE_UUID;
        }
        $member_data['nickname']        = $wechat_user_info['nickname'];
        $member_data['avatar']          = $wechat_user_info['headimgurl'];
        $member_data['create_ip']       = Request::ip();
        $member_data['last_login_ip']   = Request::ip();
        $member_data['now_ip']          = Request::ip();
        $member_data['last_login_time'] = time();
        $member_data['now_time']        = time();
        $member_data['sex']             = $wechat_user_info['sex'];
        //新增
        $member_result = $member
            ->isUpdate(false)
            ->data($member_data)
            ->save();
        $uid           = $member->uid;
        // 构建用户登录数据
        $login_data                          = [];
        $login_data['uid']                   = $uid;
        $login_data[$client_type . '_token'] = strtolower(Functions::getUUID());
        RE_LOGIN_TOKEN:
        $login_data[$client_type . '_token'] = strtolower(Functions::getUUID());
        if ($login->where($client_type . '_token', $login_data[$client_type . '_token'])->count(1) > 0) {
            goto RE_LOGIN_TOKEN;
        }
        $login_result = $login
            ->isUpdate(false)
            ->data($login_data)
            ->save();
        // 构建微信授权数据
        $wechat_data            = [];
        $wechat_data['uid']     = $uid;
        $wechat_data['openid']  = $wechat_user_info['openid'];
        $wechat_data['unionid'] = $wechat_user_info['unionid'];
        // 检测用户数据是否有关注数据
        if (isset($wechat_user_info['subscribe'])) {
            $wechat_data['subscribe'] = $wechat_user_info['subscribe'];
        }
        // 关注时间
        if (isset($wechat_user_info['subscribe_time'])) {
            $wechat_data['subscribe_time'] = $wechat_user_info['subscribe_time'];
        }
        // 关注方式
        if (isset($wechat_user_info['subscribe_scene'])) {
            $wechat_data['subscribe_scene'] = $wechat_user_info['subscribe_scene'];
        }
        $wechat_result = $wechat
            ->isUpdate(false)
            ->data($wechat_data)
            ->save();
        if ($member_result && $login_result && $wechat_result) {
            $member->commit();
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'status' => STATUS_CODE::SUCCESS,
                    'token'  => $login_data[$client_type . '_token'],
                ]
            );
        }
        $member->rollback();
        return Functions::result(
            STATUS_CODE::SUCCESS,
            [
                'status' => STATUS_CODE::FAIL,
            ]
        );
    }

    /**
     * @purpose 获取微信用户的AccessToken
     * @param $code
     */
    private static function getAccessToken($code)
    {
        //通过code换取网页授权access_token
        $url    = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . config('app.wechat.appid') . '&secret=' . config('app.wechat.secret') . '&code=' . $code . '&grant_type=authorization_code';
        $result = \Requests::get($url);
        $result = json_decode($result->body, true);
        return $result;
    }

    /**
     * @purpose 获取微信用户的用户信息
     * @param $code
     * @return array|mixed|\Requests_Response
     * @throws \Exception
     */
    private static function getWeChatUserInfo($code)
    {
        $accessTokenInfo = self::getAccessToken($code);
        if (isset($accessTokenInfo['errcode'])) {
            Log::write('wechat_access_token:' . json_encode($accessTokenInfo), 'error');
            return Functions::result(
                $accessTokenInfo['errcode'],
                $accessTokenInfo,
                $accessTokenInfo['errmsg']
            );
        }
        // 当用户没有关注公众号时不能获取到用户的基本信息,所以这里还是要利用网页授权来获取,同时获取利用全局access_token来获取用户是否关注公众号,然后合并数据
        $accessToken = Functions::getAccessToken();
        $openId      = $accessTokenInfo['openid'];
        $url1        = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $accessToken . '&openid=' . $openId . '&lang=zh_CN';
        //拉取用户信息接口
        $url     = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $accessTokenInfo['access_token'] . '&openid=' . $openId . '&lang=zh_CN';
        $result1 = \Requests::get($url1);
        $result  = \Requests::get($url);
        $result1 = json_decode($result1->body, true);
        $result  = json_decode($result->body, true);
        $result  = array_merge($result1, $result);
        if (isset($result['errcode'])) {
            Log::write('wechat_user_info:' . json_encode($result), 'error');
            return Functions::result(
                $result['errcode'],
                $result,
                $result['errmsg']
            );
        }
        return $result;
    }

    /**
     * @purpose 获取微信端当前访问的用户openid
     * @param $code
     * @return array
     */
    public static function getNowWechatUserInfo ($code)
    {
        $accessTokenInfo = self::getAccessToken($code);
        if (isset($accessTokenInfo['errcode'])) {
            Log::write('wechat_access_token:' . json_encode($accessTokenInfo), 'error');
            return Functions::result(
                $accessTokenInfo['errcode'],
                $accessTokenInfo,
                $accessTokenInfo['errmsg']
            );
        }
        $openId      = $accessTokenInfo['openid'];
        cookie('pay_openid', $openId);
        return Functions::result($accessTokenInfo);
    }
}